/************************************************************
 * Project Name         [Thinking_In_Java]
 * File Name            [MyThreadPool.java]
 * Creation Date        [04-Jul-2014]
 * 
 * Copyright© ge.y.yang@gmail.com All Rights Reserved
 * 
 * Work hard, play harder, think big and keep fit
 ************************************************************/
package pkg_08_thread.thread_pool;

import java.util.LinkedList;

/**
 * 线程池, 继承ThreadGroup.<br>
 * ThreadGroup用于处理一组线程的类, 它是一种树状结构, 它的下层节点还可以是ThreadGroup对象
 * 
 * @author 不落的太阳(Sean Yang)
 * @version 1.0
 * @since JDK 6
 * 
 */
public class MyThreadPool extends ThreadGroup {

	/** 标志线程池是否开启 */
	private boolean isAlive;
	/** 线程池中的任务队列 */
	private LinkedList<Task> taskQueue;
	/** 线程池中的线程ID */
	private int threadID;
	/** 线程池ID */
	private static int threadPoolID;

	/**
	 * 创建新的线程池, numThreads是池中的线程数
	 */
	public MyThreadPool(int numThreads) {
		super("ThreadPool-" + (threadPoolID++));
		// 设置为该线程池是的daemon属性为true, 表示当该线程池中所有线程都被销毁时, 该线程池会自动被销毁
		super.setDaemon(true);
		isAlive = true;
		// 新建一个任务队列
		taskQueue = new LinkedList<Task>();
		// 启动numThreads个工作线程
		for (int i = 0; i < numThreads; i++) {
			new PooledThread().start();
		}
	}

	/**
	 * 添加新任务
	 */
	public synchronized void performTask(Task task) {
		if (!isAlive) {
			// 线程池被关闭则抛出IllegalStateException异常
			throw new IllegalStateException();
		}
		if (task != null) {
			// 将任务放到任务队列的尾部
			taskQueue.add(task);
			// 通知工作线程取任务
			notify();
		}

	}

	/**
	 * 获取任务
	 */
	protected synchronized Task getTask() throws InterruptedException {
		// 如果任务列表为空, 而且线程池没有被关闭, 则继续等待任务
		while (taskQueue.size() == 0) {
			if (!isAlive) {
				return null;
			}
			wait();
		}
		// 取任务列表的第一个任务
		return taskQueue.removeFirst();
	}

	/**
	 * 关闭线程池, 所有线程停止, 不再执行任务
	 */
	public synchronized void close() {
		if (isAlive) {
			isAlive = false;
			// 清除任务
			taskQueue.clear();
			// 中止线程池中所有线程
			interrupt();
		}
	}

	/**
	 * 关闭线程池, 并等待线程池中的所有任务被运行完. 但是不能接受新的任务.
	 */
	public void join() {
		// 通知其他等待线程"该线程池已关闭"的消息
		synchronized (this) {
			isAlive = false;
			notifyAll();
		}
		// 等待所有线程完成
		// 首先建立一个新的线程数组.activeCount方法获取线程池中活动线程的估计数
		Thread[] threads = new Thread[activeCount()];
		// 将线程池中的活动线程拷贝到新创建的线程数组threads中.
		int count = this.enumerate(threads);
		for (int i = 0; i < count; i++) {
			try {
				// 等待线程运行结束
				threads[i].join();
			} catch (InterruptedException ex) {
			}
		}
	}

	/**
	 * 内部类, 用于执行任务的工作线程
	 */
	private class PooledThread extends Thread {

		// 构造方法
		public PooledThread() {
			// 第一个参数为该线程所在的线程组对象, 即当前线程池对象
			// 第二个参数为线程名字
			super(MyThreadPool.this, "PooledThread-" + (threadID++));
		}

		@Override
		public void run() {
			// 如果该线程没有被中止
			while (!isInterrupted()) {

				// 获取任务
				Task task = null;
				try {
					task = getTask();
				} catch (InterruptedException ex) {
				}

				// 只要线程池的任务列表不为空, getTask方法总能得到一个任务.
				// 若getTask()返回null, 则表示线程池中已经没有任务, 而且线程池已被关闭.
				if (task == null) {
					return;
				}

				// 运行任务, 吸收异常
				try {
					task.perform();
				} catch (Throwable t) {
					// 当线程组中的线程有未被捕获的异常发生时, JVM就会去调用uncaughtException方法.
					uncaughtException(this, t);
				}
			}
		}
	}
}
